package util

// 用于便于枚举的特殊数字，每位进制可以不同，支持追加高位

import (
	"bytes"
	"fmt"
	"goproject/logger"
)

// Enumerator 枚举器：每位进制可以不同的数
type Enumerator struct {
	length int
	limit  []int
	data   []int
}

// NewEnumerator 指定从0开始总位数，和每位的进制
func NewEnumerator(length int, limit []int) Enumerator {
	log := logger.GetLogger()
	if length < 0 || length != len(limit) {
		log.Panicf("长度错误 length %v limit %#v", length, limit)
	}
	for i, l := range limit {
		if l <= 0 {
			log.Panicf("限制错误 limit[ %d ] = %d", i, l)
		}
	}
	sn := Enumerator{
		length: length,
		limit:  make([]int, length),
		data:   make([]int, length),
	}
	copy(sn.limit, limit)
	return sn
}

var _ fmt.Stringer = &Enumerator{}

func (sn *Enumerator) String() string {
	var buffer bytes.Buffer
	buffer.WriteString("枚举[")
	for i := sn.length - 1; i >= 0; i-- {
		buffer.WriteString(fmt.Sprintf("%d/%d ", sn.data[i]+1, sn.limit[i]))
	}
	buffer.WriteString("]")
	return buffer.String()
}

func (sn *Enumerator) Get(pos int) int {
	log := logger.GetLogger()

	if pos < 0 || pos >= sn.length {
		log.Panicf("地址错误 %d", pos)
	}
	return sn.data[pos]
}

func (sn *Enumerator) Inc() (overflow bool) {
	if sn.Length() == 0 {
		return true
	}
	sn.data[0]++
	for i := 0; i < sn.length-1; i++ {
		if sn.data[i] == sn.limit[i] {
			sn.data[i+1]++
			sn.data[i] = 0
		}
	}
	if sn.data[sn.length-1] == sn.limit[sn.length-1] {
		overflow = true
		sn.data[sn.length-1] = 0
	}
	return
}

func (sn *Enumerator) Length() int {
	return sn.length
}

func (sn *Enumerator) PushLimit(limit int) {
	log := logger.GetLogger()

	if limit <= 0 {
		log.Panicf("限制错误 limit[ %d ] = %d", sn.limit, limit)
	}
	sn.length++
	sn.limit = append(sn.limit, limit)
	sn.data = append(sn.data, 0)
}

// Total 总个数
func (sn *Enumerator) Total() int {
	total := 1
	for _, l := range sn.limit {
		total *= l
	}
	return total
}
